package member

import (
    "fmt"
	"time"
	"math"
	"strconv"
	"dhfshop/utils/uuid"
	"dhfshop/models/member"
	"dhfshop/domain/member"
	"dhfshop/models/isv"
	"dhfshop/models/im"
	"dhfshop/domain/pay"
	"dhfshop/controllers/base"
	"github.com/astaxie/beego"
	"github.com/pkg/errors"
	"github.com/astaxie/beego/validation"
)

//Account 账户账目会计科目
type AccountController struct {
	base.BaseController
}

func (this *AccountController) List() {
	curRoleId := this.Ctx.Input.GetData("curRoleId").(int) 
	companyId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	if curUserId == 0 {
		this.ServeError("user is not login")
	    return
	}
	appIds := []string{}
	query,_,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	if curRoleId == 1 {
	    query["member_id"] = strconv.FormatInt(curUserId, 10)
	}else if curRoleId == 2 {
	    if accounts, err := isv.QueryCustAccountsByPartnerId(companyId,0,100); err != nil {
		   this.ServeError(err.Error())
		   return
		} else {
			for _, account := range accounts {
				appIds = append(appIds, account.AppId)
			}
		}
	}else{
	
	}
	l, cnt, err := member.GetAllAccounts(appIds, query,fields,order_by,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	r := struct {
		TotalCount int64                  `json:"total_count"`
		Accounts   []*member.Account `json:"accounts"`
	}{TotalCount: cnt, Accounts: l}
	this.Data["json"] = r
	this.ServeJSON()
}

// 设置优先(默认)支付方式, account 为账户类型
func (this *AccountController) SetPriorityPay() {
	v := struct {
	    AccountTypes  int    `form:"account_types" valid:"Required"`
		Enabled       bool   `form:"enabled"`
	}{Enabled: true}
	this.ParseForm(&v)
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return	
	}
	if v.AccountTypes < 1 || v.AccountTypes > 4 {
	    this.ServeError("account_types range is error")
		return
	}
	//partnerId := this.Ctx.Input.GetData("curCompanyId").(int)
	curUserId :=int64(this.Ctx.Input.GetData("curUserId").(int))
	account := &member.Account{MemberId:int64(curUserId), PriorityPay: v.AccountTypes}
	err := member.UpdateAccountById(account, "priority_pay")
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	rsp := struct {
		MemberId  int64        `json:"member_id"`
	    Modified  time.Time  `json:"modified"`
	}{MemberId: curUserId, Modified:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}


// 用户自主充值
func (this *AccountController) AccountCharge() {
	var (
		giftFee      float32 = 0.0
		srcAccount   *member.Account
		storeId     int64 = 0
	)
	v := struct {
		Amount             float32 `form:"amount" valid:"Required"`
		BalanceActivityId  int64   `form:"balance_activity_id" valid:"Required"`
	}{}
	this.ParseForm(&v)
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))   
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	//curAppId := this.Ctx.Input.GetData("curAppId").(string)   //buyer role
	//
	person , err := member.GetMemberById(int64(curUserId))
	if err != nil {
	    err = errors.Wrap(err, "GetMemberById... ")
		this.ServeError(err.Error())
		return
	}
	acPay, err := isv.GetParamsByAppIdOrSubAppId(person.AppId)
	if err != nil {
	   err = errors.Wrap(err, "GetParamsByAppIdOrSubAppId... ")
	   this.ServeError(err.Error())
	}
	orderId, _ := uuid.GetSnowFlakeId(uuid.Worker)
	outTradeNo := fmt.Sprintf("%d", orderId)   //每次需要唯一的id
	var prepayId string
	var payResponse paylayer.PayResponse
	if acPay.PayWayId == 9 {
		payResponse, prepayId, err = paylayer.ChargeRoyalPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
		if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 10{
        payResponse, prepayId, err =
		paylayer.ChargeYabandPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
    }  else if acPay.PayWayId == 11{
        payResponse, prepayId, err =
		paylayer.ChargeSuperPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
    } else if acPay.PayWayId == 12 {
	    payResponse, prepayId, err =
		paylayer.ChargeUsagms(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 13 {
	    payResponse, prepayId, err =
		paylayer.ChargeDahlPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 14 {
	    payResponse, prepayId, err =
		paylayer.ChargeWiseCashier(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 15 {
	    payResponse, prepayId, err =
		paylayer.ChargeMegaezgoPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 16 {
	    newOrderIdStr := fmt.Sprintf("%s%s", acPay.PemKey, outTradeNo[4:])
		outTradeNo = newOrderIdStr
		//
		payResponse, prepayId, err =
		paylayer.ChargeChinaUmsPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 17 {
		payResponse, prepayId, err =
		paylayer.ChargeOceanPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 18 {
		payResponse, prepayId, err =
		paylayer.ChargeQcurePay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 20 {
		payResponse, prepayId, err =
		paylayer.ChargeHnaPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 21 {
		payResponse, prepayId, err =
		paylayer.ChargeAllinPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else if acPay.PayWayId == 22 {
		payResponse, prepayId, err =
		paylayer.ChargeGpslmallPay(person.AppId,person.OpenID,outTradeNo,acPay,v.Amount)
        if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	} else {
	    body := "账户充值"
		attach := "MEMBER_CHARGE"
		if v.BalanceActivityId > 0 {
			valid := member.CheckChargeActivityValid(partnerId,time.Now().UTC(),v.Amount)
			if !valid {
				this.ServeError("charge activity is invalid, please set it")
				return
			}
		}
		payResponse, prepayId, err = paylayer.ChargeWxPay(person.OpenID,outTradeNo,body,attach,acPay,v.Amount)
		if err != nil {
		   this.ServeError(err.Error())
		   return
		}
	}
	if len(prepayId) > 3 {
	    formIdCache := &im.FormIdCache{PartnerId:partnerId,MemberId:curUserId,AppId:person.AppId,
						  FormId:prepayId,OpenId:person.OpenID,Types:"charge",Xid:outTradeNo,
						  MaxCount:3,ExpireAt:time.Now().UTC().Add(time.Hour*24*7)}
		if _, err := im.AddFormIdCache(formIdCache); err != nil {
		   beego.Debug("AddFormIdCache err:", err.Error())
		}
	}
	if v.BalanceActivityId > 0 {
		if balanceActivity, err := member.GetBalanceActivityById(v.BalanceActivityId); err == nil {
			storeId = balanceActivity.StoreId
			if v.Amount - balanceActivity.Money >= 0 {
				giftFee = balanceActivity.MoneyGift
			}
		}
	}
	srcAccount, err = member.GetAccountById(int64(curUserId))
	if err != nil {
		beego.Debug(err.Error())
	}
	log := &member.BalanceLog{
		PartnerId:    partnerId,
		StoreId:      storeId,
		MemberId:     curUserId,
		BusinessKind: 2,
		Title:        "增加余额",
		OuterNo:      outTradeNo,
		InOutType:    1,
		SrcBalance:   srcAccount.Balance,
		IncBalance:   v.Amount,
		DstBalance:   srcAccount.Balance + v.Amount,
		Present:      giftFee,  
		SrcPresent:   srcAccount.Present,
		IncPresent:   giftFee,
		DstPresent:   srcAccount.Present + giftFee,
		State:        0,    //收到充值成功消息后，更新此字段
		RelateUser:   0,
	}
	if _, err = member.AddBalanceLog(log); err != nil {
		beego.Debug(err.Error())
	}
	this.Data["json"] = payResponse
	this.ServeJSON()	
}

// 用户自主红包转余额
func (this *AccountController) BonusToBalance() {
	v := struct {
		Amount             float32 `form:"amount"`
	}{}
	this.ParseForm(&v)
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))   
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	//curAppId := this.Ctx.Input.GetData("curAppId").(string)   //buyer role
	srcAccount, err := member.GetAccountById(int64(curUserId))
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	if v.Amount > srcAccount.Bonus {
	    this.ServeError("amount is invalid")
		return
	} else if v.Amount == 0 {
	    v.Amount = srcAccount.Bonus
	} else if v.Amount < 0 {
	    this.ServeError("amount is invalid")
	    return
	} else {
	
	}
	srcBalace := srcAccount.Balance
	dstBalace := srcAccount.Balance + v.Amount
	//srcBonus := srcAccount.Bonus
	dstBonus := srcAccount.Bonus - v.Amount
	srcAccount.Balance = dstBalace
	srcAccount.Bonus = dstBonus
	if err = member.UpdateAccountById(srcAccount, "balance", "bonus"); err != nil {
		beego.Debug(err.Error())
		return
	}
	log := &member.BalanceLog{
		PartnerId:    partnerId,
		MemberId:     curUserId,
		BusinessKind: 2,
		Title:        "红包转余额",
		OuterNo:      "",
		InOutType:    1,
		SrcBalance:   srcBalace,
		IncBalance:   v.Amount,
		DstBalance:   dstBalace,
		Present:      0,  
		SrcPresent:   srcAccount.Present,
		IncPresent:   0,
		DstPresent:   srcAccount.Present,
		State:        1,    //
		RelateUser:   0,
	}
	logId, err := member.AddBalanceLog(log)
	if err != nil {
	    beego.Debug(err.Error())
	}
	rsp := struct {
		BalanceLogId  int64  `json:"balance_log_id"`
	    Created   time.Time  `json:"created"`
	}{BalanceLogId: logId, Created:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}

// 客服退款
func (this *AccountController) AccountRefund() {
	v := struct {
		ServiceTypes int     `form:"service_types" valid:"Required"`
		Title        string  `form:"title" valid:"Required"`
		OuterNo      string  `form:"outer_no"`
		Amount       float32 `form:"amount" valid:"Required"`
		RelateUserId int     `form:"relate_user_id" valid:"Required"`
	}{ServiceTypes:4,Title:"退款",OuterNo:""}
	this.ParseForm(&v)
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return	
	}
	partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	if v.Amount <= 0 || math.IsNaN(float64(v.Amount)) {
		this.ServeError("金额错误")
		return
	}
	oldAccount, err := member.GetAccountById(int64(curUserId))
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	logId, err := memberlayer.AddBalance(partnerId,curUserId,oldAccount,v.Amount,0.0,"",1)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	rsp := struct {
		BalanceLogId  int64  `json:"balance_log_id"`
	    Created   time.Time  `json:"created"`
	}{BalanceLogId: logId, Created:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}


// 冻结余额
func (this *AccountController) Freeze() {
	
	this.Data["json"] = "目前不支持"
	this.ServeJSON()
}

// 解冻金额
func (this *AccountController) Unfreeze() {

	this.Data["json"] = "目前不支持"
	this.ServeJSON()
}

// 余额日志查询
func (this *AccountController) BalanceLogList() {
	curRoleId := this.Ctx.Input.GetData("curRoleId").(int) 
	companyId :=int64(this.Ctx.Input.GetData("curCompanyId").(int))
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	query,_,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	if curRoleId == 1 {
	    query["member_id"] = strconv.FormatInt(curUserId, 10)
	}else if curRoleId == 2 {
	    query["partner_id"] = strconv.FormatInt(companyId, 10)
	}else{
	
	}
	l, cnt, err := member.GetAllBalanceLogs(query,fields,order_by,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	r := struct {
		TotalCount    int64                 `json:"total_count"`
		BalanceLogs  []*member.BalanceLog `json:"balance_logs"`
	}{TotalCount: cnt, BalanceLogs: l}
	this.Data["json"] = r
	this.ServeJSON()
}

